// Level 13 specific text helpers

define(['ash',
	'utils/DescriptionMapper',
	'text/Text',
	'text/TextBuilder',
	'game/constants/GameConstants',
	'game/constants/EnemyConstants',
	'game/constants/ItemConstants',
	'game/constants/SectorConstants',
	'game/constants/PositionConstants',
	'game/constants/MovementConstants',
	'game/constants/TradeConstants',
	'game/constants/WorldConstants',
],
	function (Ash, DescriptionMapper, Text, TextBuilder, GameConstants, EnemyConstants, ItemConstants, SectorConstants, PositionConstants, MovementConstants, TradeConstants, WorldConstants) {

		var TextConstants = {

			sentencify: function (s) {
				s = s.trim();
				if (s.length > 0) {
					if (s.endsWith(", ")) s = s.slice(0, -2);
					if (!this.isPunctuation(s[s.length - 1])) s = s + ".";
					if (s[s.length - 1] != " ") s = s + " ";
				}
				return s;
			},

			pluralify: function (s) {
				return Text.pluralify(s);
			},

			isPunctuation: function (c) {
				return c == "." || c == "!" || c == "?";
			},

			getActionName: function (baseActionID) {
				switch (baseActionID) {
					case "scavenge_heap": return "搜刮";
					case "scout_locale_i":
					case "scout_locale_u":
						return "侦查";
					case "clear_waste_r": return "清除放射性废料";
					case "clear_waste_t": return "清除有毒废料";
					case "build_out_greenhouse": return "建造温室";
					case "build_out_luxury_outpost": return "建造资源前哨";
					case "build_out_tradepost_connector": return "建造电梯";
					case "build_out_sundome": return "建造太阳穹顶";
					case "bridge_gap": return "架设桥梁";
					case "repair_item": return "修理物品";
					case "clear_workshop": return "清理车间";
					default:
						return baseActionID;
				}
			},

			getSectorName: function (isScouted, features) {
				var template = "[a-sectortype] [n-street]";
				var params = this.getSectorTextParams(features);
				var phrase = TextBuilder.build(template, params);
				return Text.capitalize(phrase);
			},

			getSectorHeader: function (hasVision, features) {
				var template = "[a-street] [a-sectortype] [n-street]";
				if (features.hasCamp) {
					template = "[n-street] 有营地";
				}
				if (features.hasGrove) {
					template = "[a-street] 园区";
				}
				if (!hasVision) {
					if (features.sunlit) {
						template = "阳光明媚的 [n-street]";
					} else {
						template = "黑暗的 [n-street]";
					}
				}
				var params = this.getSectorTextParams(features);
				var phrase = TextBuilder.build(template, params);
				return Text.capitalize(phrase);
			},

			getSectorDescription: function (hasVision, features) {
				var type = hasVision ? "sector-vision" : "sector-novision";
				var template = DescriptionMapper.get(type, features);
				if (features.hasGrove) {
					template = " [a] [a-street] 园区植物丛生。中间有一片高大的树林。虽然陌生而荒凉，但也显得莫名的宁静";
				}
				var params = this.getSectorTextParams(features);
				var phrase = TextBuilder.build(template, params);
				return Text.capitalize(phrase);
			},

			getSectorTextParams: function (features) {
				// 1) Collect options for each param based on several features
				var options = {};
				var addOptions = function (param, values) {
					if (!options[param]) options[param] = [];
					for (let i = 0; i < values.length; i++) {
						options[param].push(values[i]);
					}
				};
				// - general: options always available
				addOptions("a-street", ["安静"]);
				addOptions("n-building", ["大楼", "结构"]);
				addOptions("n-buildings", ["大楼"]);
				addOptions("a-building", ["巍巍的", "高大的", "暗的", "废弃的", "不伦不类的", "小的", "典型", "单块的", "块状的", "巨大的", "庞大的", "巨大的"]);
				addOptions("an-decos", ["废弃的长椅", "损坏的电梯"]);
				addOptions("an-items", ["瓦砾"]);
				// - sector type: determines n-sector and affects many others
				switch (features.sectorType) {
					case SectorConstants.SECTOR_TYPE_RESIDENTIAL:
						addOptions("n-sector", ["住宅区"]);
						addOptions("a-street-past", ["美丽的", "平静的", "有序的", "放松的"]);
						addOptions("n-building", ["住宅塔楼", "公寓楼", "拥有无数相同阳台的住宅楼", "住宅区块"]);
						addOptions("n-buildings", ["住宅塔楼", "公寓", "塔楼", "相同的住宅塔楼"]);
						addOptions("an-decos", ["电车轨道"]);
						addOptions("a-building", ["寂静的", "规整的", "巨大的", "对称的"]);
						addOptions("an-items", ["垃圾"]);
						break;
					case SectorConstants.SECTOR_TYPE_INDUSTRIAL:
						addOptions("n-sector", ["工业区"]);
						addOptions("a-street", ["朴素的"]);
						addOptions("a-street-past", ["高度安全的"]);
						addOptions("n-building", ["发电厂", "工厂", "仓库", "车间"]);
						addOptions("n-buildings", ["工厂", "车间", "仓库", "炼油厂"]);
						addOptions("a-building", ["退役的", "常规的", "巨大的", "奇怪的"]);
						addOptions("an-items", ["损坏的机器"]);
						break;
					case SectorConstants.SECTOR_TYPE_MAINTENANCE:
						addOptions("n-sector", ["运输大厅", "维护区域", "交通枢纽"]);
						addOptions("a-street", ["奇怪的", "混乱的", "杂乱的", "裸露的"]);
						addOptions("a-street-past", ["有序的"]);
						addOptions("n-building", ["维护中心", "缆车站", "公用建筑", "水处理站"]);
						addOptions("n-buildings", ["公用建筑", "数据中心", "控制室", "自动化控制单元"]);
						addOptions("a-building", ["退役的", "不可进入的"]);
						addOptions("an-decos", ["破损的管道", "损坏的电车"]);
						addOptions("an-items", ["电线"]);
						break;
					case SectorConstants.SECTOR_TYPE_COMMERCIAL:
						addOptions("n-sector", ["购物中心", "商业区", "办公楼群"]);
						addOptions("a-street-past", ["华丽的", "热闹的", "充满活力的"]);
						addOptions("n-building", ["购物中心", "百货商店", "办公楼", "咖啡馆", "酒吧"]);
						addOptions("n-buildings", ["购物塔楼", "购物中心", "商店", "商铺", "办公楼", "办公塔楼"]);
						addOptions("a-building", ["空的", "荒废的", "被抢劫的", "巨大的", "奇异的", "对称的", "色彩斑斓的"]);
						addOptions("an-decos", ["空的喷泉", "废弃的摊位"]);
						addOptions("an-items", ["破碎的玻璃"]);
						break;
					case SectorConstants.SECTOR_TYPE_PUBLIC:
						addOptions("n-sector", ["监狱", "游乐园", "图书馆", "公园"]);
						addOptions("a-street", ["庄严的", "肃穆的", "宏伟的", "普通的"]);
						addOptions("a-street-past", ["悠闲的", "有序的", "愉快的"]);
						addOptions("n-building", ["图书馆", "监狱", "学校", "大学建筑", "公园", "公共广场", "体育场", "地铁站", "研究实验室", "政府大楼"]);
						addOptions("n-buildings", ["公共建筑", "政府建筑"]);
						addOptions("a-building", ["空的", "不可进入的", "巨大的", "诡异的", "对称的"]);
						addOptions("an-decos", ["枯萎的树木"]);
						addOptions("an-items", ["垃圾"]);
						if (features.level > 13) addOptions("an-items", ["研究样本"]);
						break;
					case SectorConstants.SECTOR_TYPE_SLUM:
						addOptions("n-sector", ["棚户区", "垃圾填埋场"]);
						addOptions("a-street", ["破旧的", "混乱的"]);
						addOptions("a-street-past", ["阴暗的", "拥挤的", "热闹的"]);
						addOptions("n-building", ["公寓楼"]);
						addOptions("a-building", ["被遗弃的", "肮脏的", "令人沮丧的", "杂乱无章的", "灰色的", "满是涂鸦的"]);
						addOptions("n-buildings", ["棚屋", "小屋", "贫民区住宅", "公寓楼", "从未接入电网的住宅塔楼"]);
						addOptions("an-decos", ["倒塌的棚屋", "垃圾堆"]);
						addOptions("an-items", ["生锈的管道", "空罐头"]);
						break;
				}
				// - building density
				if (features.buildingDensity < 3) {
					addOptions("n-street", ["sector", "空间", "广场"]);
					if (features.sectorType == SectorConstants.SECTOR_TYPE_RESIDENTIAL || features.sectorType == SectorConstants.SECTOR_TYPE_COMMERCIAL)
						addOptions("n-street", ["广场", "庭院"]);
					addOptions("a-street", ["宽广的", "宽敞的", "巨大的"]);
				} else if (features.buildingDensity < 6) {
					addOptions("n-street", ["广场", "区域", "大厅"]);
					if (features.sectorType == SectorConstants.SECTOR_TYPE_RESIDENTIAL || features.sectorType == SectorConstants.SECTOR_TYPE_COMMERCIAL)
						addOptions("n-street", ["大道", "大街"]);
					if (features.sectorType != SectorConstants.SECTOR_TYPE_SLUM)
						addOptions("n-street", ["通路"]);
					addOptions("a-street", ["宽广的", "宽敞的"]);
				} else if (features.buildingDensity < 9) {
					addOptions("n-street", ["街道", "街道", "小巷", "综合体", "区块"]);
					addOptions("a-street", ["狭窄的"]);
				} else {
					addOptions("n-street", ["走廊", "通道", "小巷"]);
					addOptions("a-street", ["狭窄的", "狭促的", "密集的", "低矮的"]);
				}
				// - wear and damage
				switch (features.condition) {
					case SectorConstants.SECTOR_CONDITION_RUINED:
						addOptions("a-street", ["破败的", "坍塌的"]);
						addOptions("n-buildings", ["坍塌的废墟"]);
						addOptions("a-building", ["破败的", "骨架般的"]);
						break;
					case SectorConstants.SECTOR_CONDITION_DAMAGED:
						addOptions("a-street", ["损坏的", "毁坏的", "破损的"]);
						addOptions("a-building", ["损坏的"]);
						addOptions("an-decos", ["坍塌的隧道"]);
						break;
					case SectorConstants.SECTOR_CONDITION_ABANDONED:
						addOptions("a-street", ["荒凉的", "萧条的"]);
						addOptions("a-building", ["腐烂的", "荒凉的", "慢慢腐烂的", "早已被遗弃的", "坍塌的"]);
						break;
					case SectorConstants.SECTOR_CONDITION_WORN:
						addOptions("a-building", ["荒凉的", "被遗弃的", "萧条的"]);
						break;
					case SectorConstants.SECTOR_CONDITION_RECENT:
						addOptions("a-building", ["保存完好的", "现代的"]);
						break;
					case SectorConstants.SECTOR_CONDITION_MAINTAINED:
						addOptions("a-street", ["现代的", "光滑的"]);
						break;
				}
				// - sunlight
				if (features.sunlit) {
					addOptions("a-street", ["阳光充足的", "阳光普照的", "耀眼的", "明亮的", "风大的", ""]);
					if (features.wear < 5 && features.damage < 5)
						addOptions("a-street", ["闪闪发光的", "闪烁的"]);
					if (features.wear > 5)
						addOptions("a-street", ["长满杂草的"]);
					addOptions("a-building", ["生机勃勃的", "阳光充足的"]);
					addOptions("an-decos", ["顽强生长的杂草"]);
				} else {
					addOptions("a-street", ["黑暗的", "黑暗的", "阴郁的", "阴影笼罩的", "黯淡的"]);
				}
				// - hazards
				if (features.hazards.cold > 0) {
					addOptions("a-street", ["寒冷的"]);
				}
				if (features.hazards.radiation > 0) {
					addOptions("a-street", ["荒凉的"]);
					addOptions("n-building", ["核电站", "核废料存放场", "核废料处理单位"]);
					addOptions("a-building", ["废弃的"]);
					addOptions("na-items", ["丢弃的安全设备"]);
				}
				if (features.hazards.poison > 0) {
					addOptions("a-street", ["污染的"]);
					addOptions("n-building", ["化工厂", "炼油厂", "垃圾处理厂"]);
					addOptions("a-building", ["污染的"]);
					addOptions("na-items", ["使用过的医用口罩"]);
				}
				if (features.hazards.debris) {
					addOptions("a-street", ["被毁的", "损坏的", "破坏的"]);
					addOptions("n-building", ["建筑"]);
					addOptions("a-building", ["被毁的", "无法辨认的", "被掏空的"]);
					addOptions("na-items", ["瓦砾"]);
				}
				// - level population
				if (features.populationFactor == 0) {
					addOptions("a-street", ["空无一人的", "无人居住的", "荒凉的", "废弃的", "满是灰尘的"]);
					addOptions("a-building", ["被遗弃已久的", "空荡的", "污染的"]);
				} else if (features.populationFactor < 1) {
					addOptions("a-street", ["宁静的"]);
					addOptions("a-building", ["空荡的"]);
				} else {
					addOptions("a-building", ["最近被洗劫过的"]);
					addOptions("na-items", ["最近有拾荒者的迹象"]);
				}
				// - level raid danger factor
				if (features.raidDangerFactor > 1) {
					addOptions("a-street", ["被洗劫过的"]);
					addOptions("a-building", ["被洗劫过的", "损坏的", "被掠夺的", "被抢劫的"]);
				}
				// - level: architectural style / age
				if (features.level < 6) {
					addOptions("a-street", ["古老的", "古色古香的"]);
					addOptions("a-building", ["古老的", "过时的", "古色古香的", "历史悠久的", "华丽的", "巴洛克式的"]);
				} else if (features.level < 14) {
					addOptions("a-street", ["过时的"]);
					addOptions("a-building", ["过时的"]);
				} else if (features.level < 18) {
					addOptions("a-street", ["现代的"]);
					addOptions("a-building", ["现代的", "时尚的", "功能性的"]);
				}

				// 2) Build final result by selecting from options
				let result = {};
				var rand = (features.buildingDensity + features.wear + features.damage) / 30;
				var pickRandom = function (options, excluded) {
					if (!options || options.length <= 0) return "";
					var validOptions = options.filter(option => !excluded.includes(option));
					let i = Math.floor(rand * validOptions.length);
					return validOptions[i];
				};
				var selectFromOptions = function (key, num) {
					var selection = [];
					for (let i = 0; i < num; i++) {
						var sel = pickRandom(options[key], selection);
						if (sel) {
							selection.push(sel);
						} else {
							log.w("无法选择有效的 [" + key + "] " + (i + 1) + "/" + num)
							log.w(options);
						}
					}
					return selection;
				};
				result["a-sectortype"] = features.sectorType;
				result["n-sector"] = selectFromOptions("n-sector", 1);
				result["n-street"] = selectFromOptions("n-street", 1);
				result["a-street"] = selectFromOptions("a-street", 2);
				result["a-street-past"] = selectFromOptions("a-street-past", 1);
				result["n-building"] = selectFromOptions("n-building", 2);
				result["n-buildings"] = selectFromOptions("n-buildings", 2);
				result["a-building"] = selectFromOptions("a-building", 2);
				result["an-decos"] = selectFromOptions("an-decos", 2);
				result["an-items"] = selectFromOptions("an-items", 2);

				return result;
			},

			getPassageFoundMessage: function (passageVO, direction, sunlit, isBuilt) {
				switch (passageVO.type) {
					case MovementConstants.PASSAGE_TYPE_HOLE:
						if (direction === PositionConstants.DIRECTION_UP) {
							if (isBuilt) {
								return "这里有一部电梯。";
							} else {
								if (sunlit)
									return "天花板上方有一个洞。";
								else
									return "天花板上方有一个洞，一个通向黑暗的入口。";
							}
						} else {
							if (isBuilt) {
								return "这里有一个巨大的沉洞，已经安装了电梯。";
							} else {
								if (sunlit)
									return "这里有一个巨大的沉洞。远处的街道隐约可见。";
								else
									return "这里有一个巨大的沉洞。下方只见广阔的虚空。";
							}
						}
					case MovementConstants.PASSAGE_TYPE_BLOCKED:
						return "这里似乎曾经有一条楼梯，但它已经被彻底摧毁，无法修复。";
					default:
						if (isBuilt) {
							return "这里有一" + Text.addArticle(passageVO.name.toLowerCase()) + "。";
						} else {
							return "这里曾经有一" + Text.addArticle(passageVO.name.toLowerCase()) + "。";
						}
				}
			},

			getPassageRepairedMessage: function (passageType, direction, sectorPosVO, numCampsBuilt) {
				let directionName = (direction === PositionConstants.DIRECTION_UP ? "向上" : "向下");
				let includeLevelInPosition = numCampsBuilt > 1;
				switch (passageType) {
					case MovementConstants.PASSAGE_TYPE_HOLE:
						return "在 " + sectorPosVO.getInGameFormat(includeLevelInPosition) + " 处建造了电梯" + directionName;
					case MovementConstants.PASSAGE_TYPE_ELEVATOR:
						return "在 " + sectorPosVO.getInGameFormat(includeLevelInPosition) + " 处修复了电梯" + directionName;
					case MovementConstants.PASSAGE_TYPE_STAIRWELL:
						return "在 " + sectorPosVO.getInGameFormat(includeLevelInPosition) + " 处修复了楼梯间" + directionName;
					default:
						log.w("未知的通道类型: [" + passageType + "]");
						return "在 " + sectorPosVO.getInGameFormat(includeLevelInPosition) + " 处的通道" + directionName + "已准备就绪";
				}
			},

			getPassageDescription: function (passageVO, direction, isBuilt, isShort) {
				var makeHighlight = function (content) { return "<span class='hl-functionality'>" + content + "</span>"; };
				var directionName = (direction === PositionConstants.DIRECTION_UP ? "向上" : "向下");
				if (isShort) {
					switch (passageVO.type) {
						case MovementConstants.PASSAGE_TYPE_HOLE:
							if (isBuilt) {
								return "通道 " + directionName + "（电梯）（已建造）";
							} else {
								return "层级中有一个 " + (direction === PositionConstants.DIRECTION_UP ? "天花板上的孔" : "地板上的孔");
							}
						default:
							var status = isBuilt ? "修复过的" : "损坏的";
							if (passageVO.type === MovementConstants.PASSAGE_TYPE_BLOCKED) {
								status = "无法修复的";
							}
							return "通道 " + directionName + "（" + passageVO.name.toLowerCase() + "）（" + status + "）";
					}
				} else {
					switch (passageVO.type) {
						case MovementConstants.PASSAGE_TYPE_HOLE:
							if (isBuilt) {
								return "这里建造了一个全新的 " + makeHighlight("电梯 " + directionName) + " 。";
							} else {
								return "这里有一个 " + makeHighlight("孔") + " 在层级的 " + (direction === PositionConstants.DIRECTION_UP ? "天花板" : "地板") + " 上。";
							}
						default:
							var name = passageVO.name.toLowerCase() + " " + directionName;
							var article = Text.getArticle(name);
							var span = article + " " + makeHighlight(name);
							var state;
							if (isBuilt) {
								state = "并且它已被修复";
							} else if (passageVO.type === MovementConstants.PASSAGE_TYPE_ELEVATOR) {
								state = "但它已损坏";
							} else if (passageVO.type === MovementConstants.PASSAGE_TYPE_BLOCKED) {
								state = "但它无法修复";
							} else {
								state = "但它需要修复";
							}
							return "这里有 " + span + "，" + state + "。";
					}
				}
			},

			getReadBookMessage: function (itemVO, bookType, campOrdinal) {
				let features = {};
				features.bookType = bookType;
				features.bookName = itemVO.name;
				features.bookLevel = itemVO.level || 1;
				features.campOrdinal = campOrdinal;
				features.randomSeed = itemVO.itemID;
				let params = this.getBookTextParams(features);

				let template = DescriptionMapper.get("book-intro", features) + " " + DescriptionMapper.get("book-description", features);
				let phrase = TextBuilder.build(template, params);

				return phrase;
			},

			getBookTextParams: function (features) {
				var result = {};

				let levels = [];
				switch (features.bookLevel) {
					case 1:
						levels.push("简单的");
						levels.push("过时的");
						levels.push("过于简单的");
						break;
					case 2:
						levels.push("基础的");
						levels.push("常规的");
						levels.push("体面的");
						break;
					case 3:
						levels.push("高级的");
						levels.push("详细的");
						levels.push("有见地的");
						levels.push("深奥的");
						break;
				}
				result["a-level"] = DescriptionMapper.pickRandom(levels, features);

				let styles = [];
				switch (features.bookType) {
					case ItemConstants.bookTypes.science:
					case ItemConstants.bookTypes.engineering:
					case ItemConstants.bookTypes.history:
						styles.push("信息丰富的");
						styles.push("详细的");
						styles.push("枯燥的");
						styles.push("有见地的");
						styles.push("冗长的");
						styles.push("插图的");
						styles.push("科学的");
						styles.push("正式的");
						styles.push("系统化的");
						break;
					case ItemConstants.bookTypes.fiction:
						styles.push("鼓舞人心的");
						styles.push("现实的");
						styles.push("充满动作的");
						styles.push("喜剧的");
						styles.push("悲剧的");
						styles.push("浪漫的");
						styles.push("戏剧性的");
						styles.push("异想天开的");
						styles.push("无聊的");
						styles.push("黑暗的");
						styles.push("令人兴奋的");
						styles.push("令人毛骨悚然的");
						styles.push("迷人的");
						styles.push("真挚的");
						styles.push("真实的");
						styles.push("生动的");
						styles.push("缓慢的");
						styles.push("详尽的");
						styles.push("离奇的");
						break;
				}
				result["a-style"] = DescriptionMapper.pickRandom(styles, features);

				let goodAdjectives = [];
				goodAdjectives.push("雄辩的");
				goodAdjectives.push("令人难忘的");
				goodAdjectives.push("愉快的");
				goodAdjectives.push("优秀的");
				switch (features.bookType) {
					case ItemConstants.bookTypes.science:
					case ItemConstants.bookTypes.engineering:
					case ItemConstants.bookTypes.history:
						goodAdjectives.push("详细的");
						goodAdjectives.push("全面的");
						goodAdjectives.push("详尽的");
						goodAdjectives.push("引人入胜的");
						goodAdjectives.push("彻底的");
						goodAdjectives.push("有用的");
						break;
					case ItemConstants.bookTypes.fiction:
						goodAdjectives.push("杰出的");
						goodAdjectives.push("生动的");
						goodAdjectives.push("吸引人的");
						break;
				}
				result["a-good"] = DescriptionMapper.pickRandom(goodAdjectives, features);

				let badAdjectives = [];
				badAdjectives.push("单调的");
				badAdjectives.push("沉闷的");
				badAdjectives.push("无聊的");
				switch (features.bookType) {
					case ItemConstants.bookTypes.science:
					case ItemConstants.bookTypes.engineering:
					case ItemConstants.bookTypes.history:
						badAdjectives.push("不切实际的");
						badAdjectives.push("模糊的");
						break;
					case ItemConstants.bookTypes.fiction:
						badAdjectives.push("令人遗忘的");
						badAdjectives.push("缺乏创意的");
						badAdjectives.push("俗气的");
						break;
				}
				result["a-bad"] = DescriptionMapper.pickRandom(badAdjectives, features);

				let topics = [];
				switch (features.bookType) {
					case ItemConstants.bookTypes.science:
						topics.push("一种在放射性环境中生存的蛞蝓");
						topics.push("城市的基础设施");
						topics.push("海洋");
						topics.push("森林");
						topics.push("城市中的通风");
						topics.push("医学");
						topics.push("电子学");
						topics.push("如何保护自己免受阳光的有害影响");
						topics.push("生橡胶如何加工成许多有用的形式");
						topics.push("癌症治疗");
						topics.push("DNA");
						topics.push("进化");
						topics.push("板块构造");
						topics.push("电池");
						topics.push("化石");
						topics.push("发酵");
						topics.push("病毒");
						topics.push("太阳历");
						topics.push("雷达技术");
						topics.push("数学");
						topics.push("生态系统");
						topics.push("牙科");
						topics.push("计算机");
						topics.push("印刷机");
						topics.push("光学镜头");
						topics.push("肥料");

						if (features.bookLevel == 1) {
							topics.push("古代武器");
							topics.push("小苏打的多种用途");
							topics.push("板块构造");
							topics.push("一种叫做木材的古老材料");
							topics.push("食品保存");
						}
						if (features.bookLevel == 2) {
							topics.push("农作物轮作");
							topics.push("火药");
							topics.push("电力");
							topics.push("无线电技术");
							topics.push("磁罗盘");
							topics.push("行星的大气层");
							topics.push("温室维护");
							topics.push("生物化学");
						}
						if (features.bookLevel == 3) {
							topics.push("电磁学");
							topics.push("其他行星");
							topics.push("原子武器");
							topics.push("暗物质");
						}
						break;

					case ItemConstants.bookTypes.fiction:
						topics.push("灾难前的流行音乐");
						topics.push("黑暗层的生活");
						topics.push("早期移民到城市");
						topics.push("遥远的岛屿");
						topics.push("在不同星球间旅行");
						topics.push("一位著名的女演员");
						topics.push("贫民区的生活");
						topics.push("在地表上当犯罪侦探的生活");
						topics.push("城市无人居住层的鬼魂");
						topics.push("古老的火山");
						topics.push("海底旅行");
						topics.push("一种可怕的海怪");
						topics.push("一个男孩与他的蝙蝠的关系");
						break;

					case ItemConstants.bookTypes.history:
						topics.push("生物战");
						topics.push("城市前的文明");
						topics.push("农业的发展");
						topics.push("绘画的历史");
						topics.push("工业革命");
						topics.push("数字革命");
						topics.push("一个特定的民族群体");
						topics.push("城市创立后的饥荒");
						topics.push("一个城市前的全球法律组织");
						topics.push("数学的历史");
						topics.push("一个伟大的科学项目");
						topics.push("沉船");
						topics.push("奴隶制");
						topics.push("城市特定区域的魔法信仰");
						topics.push("一个历史上的独裁统治");

						if (features.bookLevel == 1) {
							topics.push("早期城市");
							topics.push("城市不同区域的建筑风格");
							topics.push("一次重大地震对城市的影响");
							topics.push("灾难前的宗教及其如何导致多次战争");
						}
						if (features.bookLevel == 2) {
							topics.push("一个强大犯罪集团的历史");
							topics.push("城市内两派之间的大战");
						}
						if (features.bookLevel == 3) {
							topics.push("一个强大犯罪集团的历史");
							topics.push("灾难前政府的形成");
						}
						break;

					case ItemConstants.bookTypes.engineering:
						topics.push("一个工业过程");
						topics.push("晶体管");
						topics.push("核反应堆");
						topics.push("无线电");
						topics.push("建筑学");
						topics.push("3D打印");
						topics.push("机器控制系统");
						topics.push("机器人设计");
						topics.push("电梯");
						topics.push("统计学");
						topics.push("电子学");
						topics.push("桥梁");

						if (features.bookLevel == 1) {
							topics.push("钢铁生产");
							topics.push("橡胶生产");
							topics.push("放射性废物管理");
						}
						if (features.bookLevel == 2) {
							topics.push("人工智能");
							topics.push("一种编程语言");
						}
						if (features.bookLevel == 3) {
							topics.push("编程");
							topics.push("机器人制造");
							topics.push("编程");
						}
						break;
				}

				result["n-topic"] = DescriptionMapper.pickRandom(topics, features);

				let objects = [];
				switch (features.bookType) {
					case ItemConstants.bookTypes.engineering:
						objects.push("晶体管");
						objects.push("你不太理解的机器，但它们似乎用于稳定城市");
						objects.push("一个称为天花板的全层太阳屏");
						objects.push("灾难前温室中的灌溉系统");
						objects.push("一种家用电器");

						if (features.bookLevel == 1) {
							objects.push("驱动旧电梯的发动机");
							objects.push("一种武器");
							objects.push("一种医疗仪器");
						}
						if (features.bookLevel == 2) {
							objects.push("覆盖整个城市层的信息网络");
							objects.push("一种飞行器");
							objects.push("一种用于收集和处理垃圾的机器人");
							objects.push("一种用于存储和传输数据的设备");
						}
						if (features.bookLevel == 3) {
							objects.push("不同类型的机器人");
							objects.push("一枚大型火箭");
							objects.push("一个污水系统");
						}
						break;
				}

				result["n-object"] = DescriptionMapper.pickRandom(objects, features);

				let themes = [];
				switch (features.bookType) {
					case ItemConstants.bookTypes.fiction:
						themes.push("来自另一个大陆的难民");
						themes.push("一个矿工第一次看到太阳");
						themes.push("一场撕开城市边缘的可怕风暴");
						themes.push("一场大洪水");
						themes.push("一个能预测天气的巫师");
						themes.push("城市内部不同派系之间的战争");
						themes.push("一个英雄领袖的崛起");
						themes.push("一个贫民区居民克服许多障碍最终在城市中晋升");
						themes.push("灾难前贫民区一个犯罪团伙的兴衰");
						themes.push("一个放弃城市居住区并试图独自找到地面的男人");
						themes.push("一组被困在城市旧部分研究站的科学家");
						themes.push("两个人在远离彼此的地方工作的浪漫故事");
						themes.push("一个官员的工作是评估个人对城市的贡献");
						themes.push("城市人民在一个政府下的统一");
						themes.push("一个思念遥远故乡的人");
						themes.push("据说在城市废弃部分游荡的鬼魂");
						themes.push("一个从未离开房间的女孩");
						themes.push("一个团队在城市一部分的电梯和电车上工作");
						themes.push("灾难前报纸办公室的复杂社会等级");
						themes.push("城市中只有老人的社区");
						themes.push("一个富有但孤独的商人的生活");
						themes.push("一个男孩与机器人的友谊");
						themes.push("一个让人们忘记自己身份的计算机程序");
						break;
				}

				result["c-theme"] = DescriptionMapper.pickRandom(themes, features);

				let facts = [];
				switch (features.bookType) {
					case ItemConstants.bookTypes.science:
						facts.push("城市的人口在灾难前已经在减少");
						facts.push("古代文明常用木材作为建筑材料，因为地面上木材丰富");
						facts.push("城市深处有几个采矿镇");
						facts.push("城市下层的维护主要由机器人完成");
						facts.push("城市大多数食品温室位于城市边缘");
						facts.push("城市的大部分水是从地面和表面收集的雨水");
						facts.push("有些动物一生都在水下生活");
						facts.push("蜘蛛丝是已知最强的天然材料");
						facts.push("香蕉是放射性的");
						facts.push("没有唾液就不能尝到食物");
						break;
					case ItemConstants.bookTypes.history:
						facts.push("在灾难前，有几个强大的采矿公司掌握了巨大的权力");
						facts.push("古代文明以四季为基础制定日历");
						facts.push("城市最初建在沼泽地上");
						facts.push("城市居住着来自几个古老文明的人");
						facts.push("曾经有一个叫城市政府的组织");
						facts.push("城市历史上经历过几次饥荒");
						facts.push("城市开始建设约700年前");
						facts.push("曾经有一段时间城市禁止所有宗教");
						facts.push("最后一个水下研究站在灾难前几十年关闭");
						break;
					case ItemConstants.bookTypes.engineering:
						facts.push("城市下层的高度不均");
						facts.push("城市的大部分曾用电灯照明");
						facts.push("城市表面曾由一个巨大的圆顶保护");
						facts.push("阳光通过复杂的镜子系统反射到城市更深处");
						facts.push("城市的一部分建在山里");
						facts.push("海洋深度污染");
						// TODO 获取类似的常见事实到特征中 / 否则
						// TODO 添加更多并按级别拆分，以避免重复
						// facts.push("城市有X层");
						// facts.push("城市最低层实际上是X");
						break;
				}

				result["c-fact"] = DescriptionMapper.pickRandom(facts, features);


				let events = [];
				switch (features.bookType) {
					case ItemConstants.bookTypes.history:
						events.push("城市曾经与数百年前的某个遥远文明发生的战争");
						events.push("城市过去500年的战争");
						events.push("城市最初几层的建设");
						events.push("从某个遥远岛屿迁移到城市的过程");
						events.push("书写之前几十年发生的所谓大饥荒");
						events.push("城市范围内政府的建立");
						events.push("一个主要的园丁起义");
						events.push("一次核电厂事故，废料释放到城市下层");
						events.push("农业从地面向温室的主要转变");
						events.push("城市发生的一系列恐怖袭击");
						events.push("第一个计算机病毒");
						events.push("城市与其他国家发生的一场毁灭性战争");
						events.push("妇女选举权");
						events.push("一系列关于用植入物增强人体的实验");
						events.push("涉及一位有影响力的政治家的丑闻");
						break;
				}

				result["c-event"] = DescriptionMapper.pickRandom(events, features);

				return result;
			},

			getReadNewspaperMessage: function (itemVO) {
				let features = {};
				features.itemName = itemVO.name;
				features.itemLevel = itemVO.level || 1;
				features.randomSeed = itemVO.itemID;
				let params = this.getNewspaperTextParams(features);

				let template = "你翻阅报纸。 " + DescriptionMapper.get("newspaper-description", features);
				let phrase = TextBuilder.build(template, params);

				return phrase;
			},


			getNewspaperTextParams: function (features) {
				let result = {};

				let events = [];
				events.push("工人罢工");
				events.push("本地庆典");
				events.push("一组难民的到来");
				events.push("三胞胎的出生");
				events.push("疾病爆发");
				events.push("失踪的贸易商队");
				events.push("鬼魂目击");
				events.push("某栋建筑中出现无法解释的光");
				switch (features.itemLevel) {
					case 1:
						events.push("发现新的狩猎场");
						events.push("一层楼板的坍塌");
						events.push("人口里程碑");
						break;
					case 2:
						events.push("发现新的冶炼技术");
						events.push("选举产生的新领导");
						events.push("音乐节");
						events.push("完成新的引水道");
						events.push("探险城市未探索的部分");
						break;
					case 3:
						events.push("发现新的建筑材料");
						events.push("发现新的药物");
						events.push("本地体育赛事");
						break;
				}
				result["c-event"] = DescriptionMapper.pickRandom(events, features);

				let topics = [];
				topics.push("本地政治");
				topics.push("本地八卦");
				topics.push("星座运势");
				topics.push("围绕定居点的植物生活");
				topics.push("城市侵蚀");
				topics.push("一个闹鬼的商业中心");
				switch (features.itemLevel) {
					case 1:
						topics.push("黑暗层中的生存技巧");
						topics.push("坠落前黑暗层的生活");
						topics.push("养蝙蝠作为宠物");
						break;
					case 2:
						topics.push("医学");
						topics.push("烹饪");
						topics.push("私人财产");
						topics.push("小规模园艺");
						break;
					case 3:
						topics.push("网络");
						topics.push("道德问题");
						break;
				}
				result["n-topic"] = DescriptionMapper.pickRandom(topics, features);

				return result;
			},

			getDonateSeedsMessage: function (itemVO) {
				return "将种子捐赠给了寺庙。僧侣们会珍惜它们，也许会有东西长出来。";
			},

			getReadResearchPaperMessage: function (itemVO) {
				let features = {};
				features.itemName = itemVO.name;
				features.itemLevel = itemVO.level || 1;
				features.randomSeed = itemVO.itemID;
				let params = this.getResearchPaperTextParams(features);

				let template = "你阅读了论文。 " + DescriptionMapper.get("researchpaper-description", features);
				let phrase = TextBuilder.build(template, params);

				return phrase;
			},

			getResearchPaperTextParams: function (features) {
				let result = {};

				let facts = [];
				facts.push("城市的解体速度超过了现有人口的维护能力");
				facts.push("城市建在沼泽地上，正慢慢沉入其中");
				facts.push("在坠落之前，海洋洋流方向发生了变化");
				facts.push("一些研究人员在坠落前几年担心火山活动");
				facts.push("在坠落前曾有研究小组调查是否可以返回地表生活");
				facts.push("城市外的空气呼吸起来是危险的");
				facts.push("在坠落前曾有一个最高机密的研究小组");
				facts.push("坠落涉及到城市表面附近的大规模爆炸");
				facts.push("坠落前的政府在太空研究上投入巨大");
				facts.push("囚犯曾被用于与太空旅行相关的秘密实验");
				facts.push("政府正在编制一个紧急情况下需要撤离的优先人员的机密名单");
				facts.push("坠落前曾有一个最高机密的基因库正在为某事准备");
				facts.push("城市政府试图掩盖大量燃料和建筑材料的储备");
				result["c-fact"] = DescriptionMapper.pickRandom(facts, features);

				let topics = [];
				topics.push("失败的太空火箭发射对城市可能造成的后果");
				topics.push("一个宇宙飞船上可以容纳的人数");
				topics.push("长距离太空旅行的可能性");
				topics.push("附近行星和星系的宜居性");
				topics.push("非常大型宇宙飞船的燃料计算");
				topics.push("可持续定居所需的人数");
				topics.push("超级火山");
				topics.push("空气质量");
				topics.push("通过歌唱控制天气的可能性");
				topics.push("开花植物对掷骰结果的影响");

				result["n-topic"] = DescriptionMapper.pickRandom(topics, features);

				return result;
			},

			getFoundStashMessage: function (stashVO) {
				switch (stashVO.stashType) {
					case ItemConstants.STASH_TYPE_ITEM:
						return "发现了一个物品储藏处。";
					case ItemConstants.STASH_TYPE_SILVER:
						return "发现了一些硬币。";
					default:
						log.w("未知的储藏类型: " + stashVO.stashType);
						return "发现了一个储藏处。";
				}
			},

			getWaymarkText: function (waymarkVO, sectorFeatures) {
				let features = Object.assign({}, sectorFeatures);
				features.waymarkType = waymarkVO.type;
				features.direction = PositionConstants.getDirectionFrom(waymarkVO.fromPosition, waymarkVO.toPosition);

				let template = DescriptionMapper.get("waymark", features);
				let params = this.getWaymarkTextParams(waymarkVO, features);
				let phrase = TextBuilder.build(template, params);

				result = phrase;
				if (GameConstants.isDebugVersion) result += " [" + waymarkVO.toPosition + "]";

				return result;
			},

			getWaymarkTextParams: function (waymarkVO, features) {
				let result = {};

				let tradePartner = TradeConstants.getTradePartner(features.campOrdinal);

				result["n-target"] = "<span class='hl-functionality'>" + this.getWaymarkTargetName(waymarkVO) + "</span>";
				result["direction"] = PositionConstants.getDirectionName(features.direction, false);
				result["n-settlement-name"] = tradePartner ? tradePartner.name : null;
				return result;
			},

			getWaymarkTargetName: function (waymarkVO) {
				switch (waymarkVO.type) {
					case SectorConstants.WAYMARK_TYPE_SPRING: return "水源";
					case SectorConstants.WAYMARK_TYPE_CAMP: return "安全";
					case SectorConstants.WAYMARK_TYPE_RADIATION: return "危险";
					case SectorConstants.WAYMARK_TYPE_POLLUTION: return "危险";
					case SectorConstants.WAYMARK_TYPE_SETTLEMENT: return "贸易";
					default:
						log.w("未知的标记类型: " + waymarkVO.type);
						return "安全";
				}
			},

			getResourceDisplayName: function (resourceName) {
				switch (resourceName) {
					case "water": return "水";
					case "food": return "食物";
					case "metal": return "金属";
					case "rope": return "绳索";
					case "herbs": return "药材";
					case "fuel": return "燃料";
					case "rubber": return "橡胶";
					case "medicine": return "药品";
					case "tools": return "工具";
					case "concrete": return "混凝土";
					case "robots": return "机器人";
				}
				return resourceName;
			},

			getHeapDisplayName: function (resourceName, features) {
				let sectorType = features.sectorType;
				let condition = features.getCondition();
				let isBadCondition = condition == SectorConstants.SECTOR_CONDITION_RUINED || condition == SectorConstants.SECTOR_CONDITION_DAMAGED;
				let isHumbleSectorType = sectorType == SectorConstants.SECTOR_TYPE_SLUM || sectorType == features.SECTOR_TYPE_MAINTENANCE || sectorType == SectorConstants.SECTOR_TYPE_INDUSTRIAL;
				let isLivable = !features.hasHazards() && !features.sunlit && features.buildingDensity > 1 && features.buildingDensity < 8;

				switch (resourceName) {
					case resourceNames.metal:
						if (features.buildingDensity > 3 && isBadCondition) return "倒塌的建筑";
						if (sectorType == SectorConstants.SECTOR_TYPE_MAINTENANCE) return "报废的车辆";
						if (features.buildingDensity < 7 && isHumbleSectorType) return "垃圾场";
						if (isLivable && condition == SectorConstants.SECTOR_CONDITION_ABANDONED) return "废弃的营地";
						return "金属堆";
				}
				return "资源堆 (" + resourceName + ")";
			},

			getLogResourceText: function (resourcesVO) {
				let msg = "";
				let replacements = [];
				let values = [];
				for (let key in resourceNames) {
					let name = resourceNames[key];
					let amount = resourcesVO.getResource(name);
					if (amount > 0) {
						msg += "$" + replacements.length + ", ";
						replacements.push("#" + replacements.length + " " + name);
						values.push(Math.round(amount));
					}
				}
				msg = msg.slice(0, -2);
				return { msg: msg, replacements: replacements, values: values };
			},

			getLogItemsText: function (items) {
				let msg = "";
				let replacements = [];
				let values = [];
				let loggedItems = {};
				for (let i = 0; i < items.length; i++) {
					let item = items[i];
					if (typeof loggedItems[item.id] === 'undefined') {
						msg += "$" + replacements.length + ", ";
						replacements.push("#" + replacements.length + " " + item.name.toLowerCase());
						values.push(1);
						loggedItems[item.id] = replacements.length - 1;
					} else {
						values[loggedItems[item.id]]++;
					}
				}
				msg = msg.slice(0, -2);
				if (Object.keys(loggedItems).length > 1) {
					let lastCommaIndex = msg.lastIndexOf(",");
					msg = msg.substring(0, lastCommaIndex) + " 和" + msg.substring(lastCommaIndex + 1);
				}
				return { msg: msg, replacements: replacements, values: values };
			},

			createTextFromLogMessage: function (msg, replacements, values, includePeriod) {
				let text = msg;
				let value = 0;
				let useValues = values.length > 0;
				for (let i = 0; i < replacements.length; i++) {
					if (useValues) {
						value = values[i];
					}
					if (value > 0 || value.length > 0 || !useValues) {
						text = text.replace("$" + i, replacements[i]);
					} else {
						text = text.replace("$" + i, "");
					}

					if (useValues) {
						text = text.replace("#" + i, values[i]);
					}
				}

				text = text.trim();
				text = text.replace(/ ,/g, "");
				text = text.replace(/^,/g, "");
				text = text.replace(/,$/g, "");
				text = text.replace(/\, \./g, ".");
				if (includePeriod && text.substr(text.length - 1) !== "." && text.substr(text.length - 1) !== "!")
					text += ".";
				text = text.trim();
				return text;
			},

			getFightChancesText: function (probability) {
				if (probability >= 0.9) {
					return "相当无害";
				}
				if (probability > 0.8) {
					return "略微令人不安";
				}
				if (probability > 0.6) {
					return "威吓性强";
				}
				if (probability >= 0.5) {
					return "有风险";
				}
				if (probability >= 0.4) {
					return "危险";
				}
				if (probability >= 0.2) {
					return "非常危险";
				}
				return "致命";
			},

			getLocaleName: function (locale, sectorFeatures, isShort) {
				let condition = sectorFeatures.getCondition();
				let modifier = "";
				let noun = "";

				// default modifiers
				switch (condition) {
					case SectorConstants.SECTOR_CONDITION_RUINED:
						modifier = "废墟";
						break;
					case SectorConstants.SECTOR_CONDITION_DAMAGED:
						modifier = "受损";
						break;
					case SectorConstants.SECTOR_CONDITION_ABANDONED:
						modifier = "废弃";
						break;
					case SectorConstants.SECTOR_CONDITION_WORN:
						modifier = "被忽视";
						break;
					case SectorConstants.SECTOR_CONDITION_RECENT:
						modifier = "空旷";
						break;
					case SectorConstants.SECTOR_CONDITION_MAINTAINED:
						modifier = "完好";
						break;
				}

				// nouns and special modifiers
				switch (locale.type) {
					case localeTypes.factory:
						noun = sectorFeatures.surface ? "办公室" : "工厂";
						break;
					case localeTypes.house:
						if (condition === SectorConstants.SECTOR_CONDITION_DAMAGED) modifier = "毁坏的";
						if (condition === SectorConstants.SECTOR_CONDITION_WORN) modifier = "破旧的";
						noun = "房屋";
						break;
					case localeTypes.lab:
						noun = "实验室";
						break;
					case localeTypes.grove:
						modifier = "繁茂的";
						noun = "树林";
						break;
					case localeTypes.market:
						noun = sectorFeatures.level > 15 ? "购物中心" : "市场";
						break;
					case localeTypes.maintenance:
						switch (condition) {
							case SectorConstants.SECTOR_CONDITION_RUINED:
								noun = "控制单元";
								break;
							case SectorConstants.SECTOR_CONDITION_DAMAGED:
								noun = "控制单元";
								break;
							case SectorConstants.SECTOR_CONDITION_ABANDONED:
								modifier = "古老的";
								noun = "网络交换机";
								break;
							case SectorConstants.SECTOR_CONDITION_WORN:
								modifier = "旧的";
								noun = "水塔";
								break;
							case SectorConstants.SECTOR_CONDITION_RECENT:
								modifier = "废弃的";
								noun = "控制单元";
								break;
							case SectorConstants.SECTOR_CONDITION_MAINTAINED:
								noun = "消防站";
								break;
							default:
						}
						break;
					case localeTypes.transport:
						noun = "车站";
						if (condition === SectorConstants.SECTOR_CONDITION_RUINED) noun = "火车站";
						if (condition === SectorConstants.SECTOR_CONDITION_WORN) modifier = "废弃的电车";
						if (condition === SectorConstants.SECTOR_CONDITION_RECENT) modifier = "缆车";
						if (condition === SectorConstants.SECTOR_CONDITION_MAINTAINED) modifier = "火车";
						break;
					case localeTypes.sewer:
						if (condition === SectorConstants.SECTOR_CONDITION_RECENT) modifier = "安静的";
						if (condition === SectorConstants.SECTOR_CONDITION_MAINTAINED) modifier = "安静的";
						noun = "下水道";
						break;
					case localeTypes.warehouse:
						if (condition === SectorConstants.SECTOR_CONDITION_RECENT) modifier = "坚固的";
						if (condition === SectorConstants.SECTOR_CONDITION_MAINTAINED) modifier = "坚固的";
						noun = "仓库";
						break;
					case localeTypes.camp:
					case localeTypes.tradingpartner:
						modifier = "外来的";
						noun = "营地";
						break;
					case localeTypes.hut:
					case localeTypes.hermit:
						if (condition === SectorConstants.SECTOR_CONDITION_RECENT) modifier = "新建的";
						if (condition === SectorConstants.SECTOR_CONDITION_MAINTAINED) modifier = "维护良好的";
						noun = "小屋";
						break;
					case localeTypes.library:
						modifier = "废弃的";
						if (sectorFeatures.level < 10) modifier = "古老的";
						noun = "图书馆";
						break;
					case localeTypes.farm:
						modifier = "被荒废的";
						if (sectorFeatures.level < 10) modifier = "古老的";
						noun = "农场";
					default:
						log.w("未知的地点类型: " + locale.type);
						noun = "建筑";
						break;
				}

				return isShort ? noun : (modifier + " " + noun).trim();
			},

			getWorkshopName: function (resource) {
				switch (resource) {
					case resourceNames.fuel: return "炼油厂";
					case resourceNames.rubber: return "橡胶厂";
					default: return "工坊";
				}
			},

			getSpringName: function (featuresComponent) {
				let hasHazards = featuresComponent.hazards.hasHazards();
				let type = featuresComponent.sectorType;
				if (featuresComponent.ground && featuresComponent.buildingDensity < 6
					&& !hasHazards && type != SectorConstants.SECTOR_TYPE_INDUSTRIAL) {
					return "小溪";
				}
				if (type == SectorConstants.SECTOR_TYPE_SLUM && featuresComponent.damage < 3 && featuresComponent.buildingDensity < 8) {
					return "旧水井";
				}
				if (type != SectorConstants.SECTOR_TYPE_SLUM && type != SectorConstants.SECTOR_TYPE_MAINTENANCE && featuresComponent.wear < 5 && featuresComponent.damage < 3) {
					return "饮水机";
				}
				if (featuresComponent.wear > 6 || featuresComponent.damage > 3) {
					return "水管渗漏";
				}
				return "水塔";
			},

			getEnemyText: function (enemyList, sectorControlComponent) {
				let result = "";
				var enemyActiveV = this.getEnemyActiveVerb(enemyList);
				var enemyNounSector = this.getEnemyNoun(enemyList, true, true);
				result += enemyActiveV + " " + enemyNounSector;
				return result;
			},

			getEnemyNoun: function (enemyList, detailed, pluralify) {
				var baseNoun = this.getCommonText(enemyList, "nouns", detailed ? "name" : "", "某人或某物", true, pluralify);
				if (detailed) {
					return baseNoun;
				} else {
					var parts = baseNoun.split(" ");
					return parts[parts.length - 1];
				}
			},

			getEnemyGroupNoun: function (enemyList) {
				return this.getCommonText(enemyList, "groupN", "", "群体", false)
			},

			getEnemyActiveVerb: function (enemyList) {
				return this.getCommonText(enemyList, "activeV", "", "占据", false);
			},

			getEnemeyDefeatedVerb: function (enemyList) {
				return this.getCommonText(enemyList, "defeatedV", "", "击败", false);
			},

			getScaResourcesString: function (discoveredResources, knownResources, resourcesScavengable) {
				var s = "";
				for (var key in resourceNames) {
					var name = resourceNames[key];
					var amount = resourcesScavengable.getResource(name);
					if (amount > 0 && discoveredResources.indexOf(name) >= 0) {
						var amountDesc = "稀缺";
						if (amount == WorldConstants.resourcePrevalence.RARE) amountDesc = "罕见";
						if (amount == WorldConstants.resourcePrevalence.DEFAULT) amountDesc = "稀缺";
						if (amount == WorldConstants.resourcePrevalence.COMMON) amountDesc = "常见";
						if (amount == WorldConstants.resourcePrevalence.ABUNDANT) amountDesc = "富裕";
						if (GameConstants.isDebugVersion) amountDesc += " " + Math.round(amount);
						let nameMap = {
							water: '水',
							food: "食物",
							metal: "金属",
							rope: "绳索",

							herbs: "药材",
							fuel: "燃料",
							rubber: "橡胶",

							medicine: "药品",
							tools: "工具",
							concrete: "混凝土",
							robots: "机器人",
						}

						s += (nameMap[key] !== undefined ? nameMap[key] : key) + " (" + amountDesc + "), ";
					} else if (amount > 0 && knownResources.indexOf(name) >= 0) {
						s += key + " (??), ";
					}
				}
				if (s.length > 0) return s.substring(0, s.length - 2);
				else if (resourcesScavengable.getTotal() > 0) return "未知";
				else return "无";
			},

			getScaItemString: function (discoveredItems, knownItems, itemsScavengeable) {
				let validItems = [];
				for (let i = 0; i < itemsScavengeable.length; i++) {
					let id = itemsScavengeable[i];
					if (knownItems.indexOf(id) < 0) continue;
					let item = ItemConstants.getItemDefinitionByID(id);
					if (!item) continue;
					validItems.push(item.name);
				}

				if (validItems.length == 0) {
					if (itemsScavengeable.length > 0) {
						return "某些成分";
					} else {
						return "无";
					}
				}

				return validItems.join(", ");
			},

			getMovementBlockerName: function (blockerVO, enemiesComponent, gangComponent) {
				switch (blockerVO.type) {
					case MovementConstants.BLOCKER_TYPE_GANG:
						let enemies = this.getAllEnemies(null, gangComponent);
						var groupNoun = this.getEnemyGroupNoun(enemies);
						var enemyNoun = this.getEnemyNoun(enemies);
						return groupNoun + " 的 " + Text.pluralify(enemyNoun);
					default:
						return blockerVO.name;
				}
				return "";
			},

			getMovementBlockerAction: function (blockerVO, enemiesComponent, gangComponent) {
				switch (blockerVO.type) {
					case MovementConstants.BLOCKER_TYPE_GAP: return "修补桥梁";
					case MovementConstants.BLOCKER_TYPE_WASTE_TOXIC: return "清理废料";
					case MovementConstants.BLOCKER_TYPE_WASTE_RADIOACTIVE: return "清理废料";
					case MovementConstants.BLOCKER_TYPE_GANG:
						let enemies = this.getAllEnemies(null, gangComponent);
						return "与 " + this.getEnemyNoun(enemies, false, true) + " 战斗";
				}
			},

			getAllEnemies: function (enemiesComponent, gangComponent) {
				let enemies = [];
				if (enemiesComponent && enemiesComponent.possibleEnemies) {
					enemies = enemiesComponent.possibleEnemies.concat();
				}
				if (gangComponent) {
					for (let i = 0; i < gangComponent.enemyIDs.length; i++) {
						var gangEnemy = EnemyConstants.getEnemy(gangComponent.enemyIDs[i]);
						enemies.push(gangEnemy);
					}
				}
				return enemies;
			},

			getUnblockedVerb: function (blockerType) {
				switch (blockerType) {
					case MovementConstants.BLOCKER_TYPE_GAP: return "已修复";
					case MovementConstants.BLOCKER_TYPE_WASTE_TOXIC: return "已清理";
					case MovementConstants.BLOCKER_TYPE_WASTE_RADIOACTIVE: return "已清理";
					case MovementConstants.BLOCKER_TYPE_GANG: return "已击败";
					case MovementConstants.BLOCKER_TYPE_DEBRIS: return "已清理";
				}
			},

			// get common description word for a list of objects that contain possible words are in arrays named objectAttribute
			// if nothing common is found, defaultWord is returned
			// is allowSeveral, two common words can be returned if one doesn't cover all objects
			getCommonText: function (objectList, objectAttribute, objectDetailAttribute, defaultWord, allowSeveral, pluralify) {
				var allWords = [];
				var allDetails = [];
				var minimumWords = [];
				for (var i1 in objectList) {
					var o = objectList[i1];
					if (!o) continue;
					for (var j1 in o[objectAttribute]) {
						var word = o[objectAttribute][j1];
						var detail = objectDetailAttribute ? o[objectDetailAttribute] : "";
						if (!word) continue;
						if ($.inArray(word, allWords) < 0) allWords.push(word);
						if (objectDetailAttribute && $.inArray(detail, allDetails) < 0) allDetails.push(detail);
						if (j1 == 0 && $.inArray(word, minimumWords) < 0) minimumWords.push(word);
					}
				}

				var validWords = [];
				for (var i2 in allWords) {
					var word = allWords[i2];
					var valid = true;
					for (var j2 in objectList) {
						var o = objectList[j2];
						if ($.inArray(word, o[objectAttribute]) < 0) valid = false;
					}
					if (valid) validWords.push(word);
				}

				var validDetail = "";
				if (objectDetailAttribute) {
					for (var i3 in allDetails) {
						var detail = allDetails[i3];
						var valid = true;
						for (var j3 in objectList) {
							var o = objectList[j3];
							if (o[objectDetailAttribute] != detail) valid = false;
						}
						if (valid) validDetail = detail;
					}
				}

				// log.i("getCommonText " + objectAttribute + " | " + validDetail + " | " + validWords.join(",") + " | " + minimumWords.join(",") + " | " + defaultWord);
				// log.i(objectList)

				if (validDetail.length > 0) {
					return pluralify ? Text.pluralify(validDetail) : validDetail;
				} else if (validWords.length > 0) {
					return pluralify ? Text.pluralify(validWords[0]) : validWords[0];
				} else if (allowSeveral && minimumWords.length > 1) {
					return pluralify ? (Text.pluralify(minimumWords[0]) + " 和 " + Text.pluralify(minimumWords[1])) : (minimumWords[0] + " 和 " + minimumWords[1]);
				} else {
					return defaultWord;
				}
			},

			getListText: function (list, max) {
				if (!list || list.length == 0) {
					return "无";
				} else if (list.length == 1) {
					return list[0];
				} else if (list.length == 2) {
					return list[0] + " 和 " + list[1];
				} else if (max && list.length > max) {
					let displayedList = list.slice(0, max);
					let numHiddenItems = list.length - displayedList.length;
					return displayedList.join(", ") + ", +" + numHiddenItems;
				} else {
					return list.join(", ");
				}
			},

		};

		function initSectorTexts() {
			let wildcard = DescriptionMapper.WILDCARD;

			let t_R = SectorConstants.SECTOR_TYPE_RESIDENTIAL;
			let t_I = SectorConstants.SECTOR_TYPE_INDUSTRIAL;
			let t_M = SectorConstants.SECTOR_TYPE_MAINTENANCE;
			let t_C = SectorConstants.SECTOR_TYPE_COMMERCIAL;
			let t_P = SectorConstants.SECTOR_TYPE_PUBLIC;
			let t_S = SectorConstants.SECTOR_TYPE_SLUM;

			// brackets for values like building density, wear, damage
			let b0 = [0, 0];
			let bfull = [10, 10];
			let b12 = [0, 5];
			let b22 = [5, 10];
			let b13 = [0, 3];
			let b23 = [4, 6];
			let b33 = [7, 10];

			let lmodern = [15, 100];
			let lold = [10, 18];

			// TODO add some sunlit sector specific descriptions (can we determine WHY sunlit? edge / hole)

			// default descriptions (player has vision)
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [n-street] 在看起来像是 [a] [a-building] [n-building] 的前面");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-street] 在两个 [a-building] [n-buildings] 之间");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-street] 两者之间 [n-buildings] 和一些 [a-building] [n-buildings] 两边");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-sectortype] [n-street] 有几个 [a-building] [n-buildings]");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-sector] 满是 [an-items] 和 [an-items]");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-street] 两侧排满了 [a-building] [n-buildings]");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-street] 被 [n-buildings] 环绕");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-street] 被 [a-building] [n-buildings] 环绕");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [n-street] 有一些 [an-decos] 和 [a-building] [n-buildings]");
			DescriptionMapper.add("sector-vision", { sectorType: wildcard }, "[a] [a-street] [n-street] 在一些 [n-buildings] 之间");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: false }, "[a] [n-street] 在一个巨大的支撑着上方层的柱子底部");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: false, wear: b12, sunlit: false, debris: b0 }, "[a] [a-street] [n-street] 具有长时间被遗弃的建筑物，上面覆盖着奇怪的苔藓");
			DescriptionMapper.add("sector-vision", { buildingDensity: b0, isGroundLevel: false }, "一套桥梁和通道系统，连接着几个建筑物，通向下方的令人眩晕的开口");
			DescriptionMapper.add("sector-vision", { buildingDensity: b12, isGroundLevel: false, campable: false }, "[a] [a-street] 桥梁横跨下方的层次，有分开的层次供电车轨道、设施和行人使用");
			DescriptionMapper.add("sector-vision", { buildingDensity: b22 }, "某种 [a] [a-sectortype] 复杂区域，通道狭窄");
			DescriptionMapper.add("sector-vision", { buildingDensity: b13 }, "一个宽阔的广场，一边是 [a] [a-building] [n-building]，另一边是 [a] [a-building] [n-building] 的残骸");
			DescriptionMapper.add("sector-vision", { buildingDensity: b23, isSurfaceLevel: false, sunlit: false }, "[a] [a-street] [n-street] 在广袤的 [n-building] 中");
			DescriptionMapper.add("sector-vision", { buildingDensity: b23, isSurfaceLevel: false }, "[a] [n-street] 拥有多个层次的通道沿着周围的 [a-sectortype] 建筑物的墙壁");
			DescriptionMapper.add("sector-vision", { buildingDensity: b33 }, "某种 [a] [a-sectortype] 走廊，位于两个巨大的 [n-buildings] 之间，几乎没有足够的空间走动");
			DescriptionMapper.add("sector-vision", { buildingDensity: b33 }, "[a] [a-street] [n-street] 被 [a-building] [n-buildings] 和 [an-decos] 填满，几乎没有空间通过");
			DescriptionMapper.add("sector-vision", { buildingDensity: b33 }, "[a] [a-street] 小巷在两个 [a-building] [n-buildings] 之间");
			DescriptionMapper.add("sector-vision", { wear: b13, sunlit: false, level: lmodern, debris: b0 }, "[a] [a-street] [n-street] 在高耸的 [n-buildings] 之间，两侧排列着枯萎的树木，这些树木直到最近才在人工光线下繁茂生长");
			DescriptionMapper.add("sector-vision", { wear: b13, level: lmodern, isSurfaceLevel: false }, "一个 [n-street] 在一些骨架建筑之间，这些建筑似乎在尚未完工时就已被遗弃");
			DescriptionMapper.add("sector-vision", { wear: b23, damage: b0 }, "一个曾经的 [n-sector] 仍残留着 [a] [a-street-past] 的氛围");
			DescriptionMapper.add("sector-vision", { wear: b23, damage: b0 }, "曾经的 [a-street-past] [n-sector] 中间有一些 [an-decos] 和 [a] [a-building] [n-building]");
			DescriptionMapper.add("sector-vision", { wear: b33 }, "[a] [a-building] 建筑，其原始用途难以确定，剥离至裸露的混凝土");
			DescriptionMapper.add("sector-vision", { buildingDensity: b22, wear: b33 }, "[a] [a-street] 走廊中有散落的垃圾，来自早已消失的居民");
			DescriptionMapper.add("sector-vision", { wear: b33, isSurfaceLevel: false }, "[a] [a-street] [a-sectortype] [n-street] 上方笼罩着几处大型无法识别的废墟");
			DescriptionMapper.add("sector-vision", { wear: b33 }, "一个完全被毁坏的 [a-sectortype] [n-street]");
			DescriptionMapper.add("sector-vision", { wear: b33 }, "一个被瓦砾覆盖的 [n-street] 被 [a-sectortype] 建筑的崩溃残骸包围");
			DescriptionMapper.add("sector-vision", { damage: b22 }, "一个曾经的 [a-sectortype] 区域，其中 [n-buildings] 和 [n-buildings] 处于废墟中");
			DescriptionMapper.add("sector-vision", { damage: b33 }, "一个完全毁坏的 [a-sectortype] [n-street]");
			DescriptionMapper.add("sector-vision", { damage: b22, buildingDensity: b12 }, "一个 [a-street] [n-street] 两侧是被毁坏的建筑物残骸");
			DescriptionMapper.add("sector-vision", { damage: b22, buildingDensity: b22 }, "一个充满瓦砾的 [n-street]，通过变得困难");
			DescriptionMapper.add("sector-vision", { sectorType: t_R }, "一个小的 [n-street] 在一些 [a-building] 公寓塔楼之间");
			DescriptionMapper.add("sector-vision", { sectorType: t_R, buildingDensity: b23, isSurfaceLevel: false }, "一个 [a-street] [n-street] 沿着一面巨大的墙壁延伸到上方的层次，墙上点缀着 [a-building] 公寓");
			DescriptionMapper.add("sector-vision", { sectorType: t_R, buildingDensity: b12, level: [6, 100] }, "一个 [n-street] 两侧是几个相同的狭窄住宅塔楼");
			DescriptionMapper.add("sector-vision", { sectorType: t_R, buildingDensity: b23 }, "一个 [n-street] 在一个 [a-building] 住宅建筑外面，具有令人眩晕的几何形状阳台");
			DescriptionMapper.add("sector-vision", { sectorType: t_R, level: lmodern }, "一个广场，被曾经相当舒适的公寓塔楼包围");
			DescriptionMapper.add("sector-vision", { sectorType: t_I }, "一个位于巨大的 [a-building] 工业综合体外的街道");
			DescriptionMapper.add("sector-vision", { sectorType: t_I, buildingDensity: b13 }, "一个空旷的广场，带有一些损坏的容器和巨大的生锈机械臂");
			DescriptionMapper.add("sector-vision", { sectorType: t_I, buildingDensity: b23 }, "[a] [n-street] 在两块看起来像是 [a-building] 控制室和办公室的建筑之间");
			DescriptionMapper.add("sector-vision", { sectorType: t_M }, "[a] [a-street] [n-street] 在 [a] [n-building] 后面，低矮的天花板上交织着旧电线和管道");
			DescriptionMapper.add("sector-vision", { sectorType: t_M }, "一个荒凉的 [n-street] 被破损的电缆系统和维护管道交织");
			DescriptionMapper.add("sector-vision", { sectorType: t_M, isSurfaceLevel: false }, "一个在巨大桥梁下的被淹没的通道，远处可以看到 [a-building] 建筑");
			DescriptionMapper.add("sector-vision", { sectorType: t_M }, "一个在机器运行的城市设施中的被遗忘的空间，光滑的表面上只有管道和管线");
			DescriptionMapper.add("sector-vision", { sectorType: t_M, level: lold, buildingDensity: b13 }, "一个宽敞的广场，中间有一个控制室，旧电缆系统线路向各个方向延伸");
			DescriptionMapper.add("sector-vision", { sectorType: t_C }, "[a] [a-street] 购物街，残留着各种商店和咖啡馆");
			DescriptionMapper.add("sector-vision", { sectorType: t_C }, "一个 [n-street] 在一些商业建筑之间，其 [a-building] 墙壁上覆盖着破损的屏幕拼接");
			DescriptionMapper.add("sector-vision", { sectorType: t_C, wear: b12 }, "一个 [a-street] [n-street] 拥挤的小商店、广告牌和多个层次的 kiosks");
			DescriptionMapper.add("sector-vision", { sectorType: t_C, buildingDensity: b12, isSurfaceLevel: false }, "一个 [n-street] 建筑物附着在水平层的天花板上，像巨大的钟乳石一样")
			DescriptionMapper.add("sector-vision", { sectorType: t_C, buildingDensity: b12, isSurfaceLevel: false }, "一个围绕巨大雕像建造的广场，四周被 [a-building] 商店的店面包围");
			DescriptionMapper.add("sector-vision", { sectorType: t_C, buildingDensity: b13 }, "一个位于高架建筑下的广场，中间曾经有一个瀑布");
			DescriptionMapper.add("sector-vision", { sectorType: t_C, buildingDensity: b13 }, "[a] 宽阔的围栏平台附属于一个巨大的塔楼，可以俯瞰下方的 [a-street] 街道");
			DescriptionMapper.add("sector-vision", { sectorType: t_C, buildingDensity: b13 }, "一个被 [a-building] 办公楼包围的圆形庭院");
			DescriptionMapper.add("sector-vision", { sectorType: t_C, buildingDensity: b22, wear: b33 }, "[a] [a-building] 建筑，其原始用途难以确定，剥离至混凝土，中间有一个令人印象深刻的螺旋楼梯");
			DescriptionMapper.add("sector-vision", { sectorType: t_P }, "[a] [n-street] 被一座巨大的建筑主导，这座建筑看起来曾经是某种公共设施");
			DescriptionMapper.add("sector-vision", { sectorType: t_P }, "一段废弃的高速公路，两侧有一些较小的建筑物");
			DescriptionMapper.add("sector-vision", { sectorType: t_P, buildingDensity: b12 }, "[a] [a-street] [n-street] 被一排庄严的雕像主导");
			DescriptionMapper.add("sector-vision", { sectorType: t_P, buildingDensity: b12, wear: b22 }, "一个装饰华丽的大厅，似乎曾经是一个大型车站，带有圆顶屋顶、巨大的吊灯和两侧的小摊位");
			DescriptionMapper.add("sector-vision", { sectorType: t_P, buildingDensity: b13 }, "一个开阔的空间，看起来曾经可能用于某种运动");
			DescriptionMapper.add("sector-vision", { sectorType: t_P, buildingDensity: b33 }, "[a] [a-street] [n-street] 在两座巨大 [n-buildings] 之间，几乎没有足够的空间通行");
			DescriptionMapper.add("sector-vision", { sectorType: t_S, buildingDensity: b33, wear: b22 }, "[a] [a-street] [n-street] 被 [a-building] 住宅包围（部分被覆盖），这些住宅已经被遗弃一段时间");
			DescriptionMapper.add("sector-vision", { sectorType: t_S, buildingDensity: b13 }, "一个宽广的广场，墙壁支撑着几个临时搭建的小棚子");
			DescriptionMapper.add("sector-vision", { level: 14, buildingDensity: b13 }, "一个巨大大厅，看起来曾经用于某种存储区域，天花板上有生锈的自动化机械手");
			DescriptionMapper.add("sector-vision", { level: 14, buildingDensity: b23 }, "[a] [a-street] 通过两个废弃的、有围墙的核反应堆之间的通道");
			DescriptionMapper.add("sector-vision", { level: 14, buildingDensity: b23 }, "[a] [a-street] [n-street] 在一个巨大的工业加工综合体外，所有入口紧紧关闭");
			DescriptionMapper.add("sector-vision", { level: 14, buildingDensity: b33 }, "[a] [a-street] 通道，看起来曾经用于在这个层级的各种设施之间运输货物");
			DescriptionMapper.add("sector-vision", { level: 14, buildingDensity: b33 }, "[a] [a-sectortype] 走廊，曾经看起来很干净，但现在满是碎片");
			DescriptionMapper.add("sector-vision", { level: 14, buildingDensity: b33 }, "一个窗户通道在核设施的废墟上方");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b13 }, "城市下方一个宽敞的开放空间，泥土、草和其他植物从混凝土地板的裂缝中冒出来");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b13 }, "一个古老的广场，早已被遗忘，巨大的柱子支撑着上方的城市");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b13 }, "一个开放的空间，可能曾经是一个公园，现在被奇异的植物和蘑菇覆盖");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b13, sectorType: t_R }, "一个辉煌的 [a-street] 排列着现代住宅塔楼，现在全都被遗弃");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b23 }, "[a] [a-street] 街道在破败的古老 [a-sectortype] 建筑之间");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b23 }, "一个无遮盖的街道，下方的下一层城市高高悬浮，两侧是废墟");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b33 }, "一个通过古老建筑的通道");
			DescriptionMapper.add("sector-vision", { isGroundLevel: true, buildingDensity: b33 }, "一条铺有裂缝的狭窄街道");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b13 }, "一个曾经的 [a-street-past] 广场，周围环绕着玻璃穹顶的通道和小商店");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b13 }, "一个宽广的 [n-street]，废料被风吹动");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b13, sectorType: t_P }, "一个大广场，中间有一座华丽的公共建筑");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b23 }, "一个 [a-street] 街道上点缀着广告牌和破损的屏幕，周围被高大的建筑包围");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b23 }, "一个暴露的街道，两侧是高大的建筑，强风吹动着");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b23 }, "一个多层街道，下方有电车的空间，下面有行人和小商店");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b33 }, "[a] [a-street] [n-street] 在高大、装饰华丽的 [n-buildings] 之间");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b33 }, "[a] [a-street] 通道在曾经是两个购物中心的地方");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, buildingDensity: b33 }, "[a] [a-street] [n-street] 风在狭窄的通道中不断呼啸");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, sectorType: t_C }, "[a] [a-street] [n-street] 在曾经是两个购物中心的地方");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, sectorType: t_C }, "一个宏伟的购物中心，似乎曾经满是出售奢侈品的商店");
			DescriptionMapper.add("sector-vision", { isSurfaceLevel: true, sectorType: t_I }, "[a] [a-street] 配有宏伟的办公楼");
			DescriptionMapper.add("sector-vision", { debris: b22 }, "一个充满废料的 [n-street]");
			DescriptionMapper.add("sector-vision", { debris: b22, sectorType: t_R }, "[a] [n-street] 被几个完全毁坏的住宅塔楼夹在中间");

			// descriptions when player has no vision (lamp/sunglasses)
			// 玩家没有视野（灯/太阳镜）时的描述
			DescriptionMapper.add("sector-novision", { sunlit: false, buildingDensity: b0 }, "城市内部一个罕见的空旷空间；没有地板或墙壁，没有建筑物，什么都没有。只有广阔的黑暗");
			DescriptionMapper.add("sector-novision", { sunlit: false, buildingDensity: b13 }, "一条宽阔的街道或走廊。在广阔的黑暗中很难找到任何东西");
			DescriptionMapper.add("sector-novision", { sunlit: false, buildingDensity: b23, wear: b22 }, "一条或走廊带有被遗弃的气息。在黑暗中细节渐渐消失");
			DescriptionMapper.add("sector-novision", { sunlit: false, buildingDensity: b23, wear: b12 }, "一条安静的街道或走廊。在黑暗中细节渐渐消失");
			DescriptionMapper.add("sector-novision", { sunlit: false, buildingDensity: b33 }, "一个狭窄的通道，几乎没有足够的空间行走。在黑暗中摸索前行");
			DescriptionMapper.add("sector-novision", { sunlit: false }, "城市内部的一个空间，被黑暗隐藏");
			DescriptionMapper.add("sector-novision", { sunlit: true, buildingDensity: b0 }, "城市内部一个罕见的空旷空间；没有地板或墙壁，没有建筑物，什么都没有。只有广阔的空旷");
			DescriptionMapper.add("sector-novision", { sunlit: true, buildingDensity: b13 }, "一条宽阔的街道或走廊。在刺眼的阳光中很难找到任何东西");
			DescriptionMapper.add("sector-novision", { sunlit: true, buildingDensity: b23, wear: b22 }, "一条或走廊带有被遗弃的气息。在刺眼的光线中细节渐渐消失");
			DescriptionMapper.add("sector-novision", { sunlit: true, buildingDensity: b23, wear: b12 }, "一条安静的街道或走廊。在阳光中细节渐渐消失");
			DescriptionMapper.add("sector-novision", { sunlit: true, buildingDensity: b33 }, "一个狭窄的通道，几乎没有足够的空间行走。在刺眼的光线中摸索前行");
			DescriptionMapper.add("sector-novision", { sunlit: true }, "城市内部的一个空间，在刺眼的光线中模糊不清");
		}

		function initWaymarkTexts() {
			var wildcard = DescriptionMapper.WILDCARD;

			var t_R = SectorConstants.SECTOR_TYPE_RESIDENTIAL;
			var t_I = SectorConstants.SECTOR_TYPE_INDUSTRIAL;
			var t_M = SectorConstants.SECTOR_TYPE_MAINTENANCE;
			var t_C = SectorConstants.SECTOR_TYPE_COMMERCIAL;
			var t_P = SectorConstants.SECTOR_TYPE_PUBLIC;
			var t_S = SectorConstants.SECTOR_TYPE_SLUM;

			var wt_C = SectorConstants.WAYMARK_TYPE_CAMP;
			var wt_W = SectorConstants.WAYMARK_TYPE_SPRING;
			var wt_P = SectorConstants.WAYMARK_TYPE_POLLUTION;
			var wt_R = SectorConstants.WAYMARK_TYPE_RADIATION;
			var wt_S = SectorConstants.WAYMARK_TYPE_SETTLEMENT;

			// brackets for values like building density, wear, damage
			var b0 = [0, 0];
			var b12 = [0, 5];
			var b22 = [5, 10];

			var lt1 = [0, 0.999];
			var gte1 = [1, 100];

			DescriptionMapper.add("waymark", { sectorType: wildcard }, "一个墙壁旁的走廊上，朝 [direction] 方向画了一个大大的 [n-target] 符号");
			DescriptionMapper.add("waymark", { sectorType: wildcard }, "有一个涂鸦，上面写着 [n-target] 和一个指向 [direction] 的箭头");
			DescriptionMapper.add("waymark", { buildingDensity: b12 }, "一些砖块被排列成一个指向 [direction] 的箭头形状，还有一个粗糙的符号，可能代表 [n-target]");
			DescriptionMapper.add("waymark", { waymarkType: wt_C }, "你看到一些涂鸦，上面有箭头指向 [direction] 和 '安全'、'避难所' 等字样");
			DescriptionMapper.add("waymark", { waymarkType: wt_R }, "朝 [direction] 方向前进时，墙上有多个骷髅标记");
			DescriptionMapper.add("waymark", { waymarkType: wt_P }, "朝 [direction] 方向前进时，墙上有多个骷髅标记");
			DescriptionMapper.add("waymark", { waymarkType: wt_S }, "在一个朝 [direction] 方向的通道旁，有一个墙上的金属牌匾，上面写着 '[n-settlement-name]'");
			DescriptionMapper.add("waymark", { waymarkType: wt_W }, "街上画了一支蓝色箭头，指向 [direction]");
			DescriptionMapper.add("waymark", { sectorType: t_C }, "一个商店的广告牌被涂改过，上面画了一个指向 [direction] 的箭头和 [n-target] 这个词");
			DescriptionMapper.add("waymark", { sectorType: t_I }, "一个方向标志被涂改了。朝 [direction] 方向写着 [n-target]");
			DescriptionMapper.add("waymark", { sectorType: t_M }, "天花板附近的管道上画了箭头。其中一个指向 [direction] 的箭头旁边有一个 [n-target] 的符号");
			DescriptionMapper.add("waymark", { sectorType: t_P }, "一个雕像手里拿着一个粗糙的标志，说明 [direction] 方向有 [n-target]");
			DescriptionMapper.add("waymark", { sectorType: t_S }, "有几个磨损的海报指示 [direction] 方向有 [n-target]");
		}

		function initBookTexts() {
			var wildcard = DescriptionMapper.WILDCARD;

			let t_S = ItemConstants.bookTypes.science;
			let t_F = ItemConstants.bookTypes.fiction;
			let t_H = ItemConstants.bookTypes.history;
			let t_E = ItemConstants.bookTypes.engineering;

			let l_1 = 1;
			let l_2 = 2;
			let l_3 = 3;

			DescriptionMapper.add("book-intro", { bookType: wildcard }, "你读了这本书.");
			DescriptionMapper.add("book-intro", { bookLevel: l_1 }, "你翻阅这本书.");
			DescriptionMapper.add("book-intro", { bookLevel: l_2 }, "你研究这本书.");
			DescriptionMapper.add("book-intro", { bookLevel: l_3 }, "你花了一些时间研究这本书.");
			DescriptionMapper.add("book-intro", { bookType: t_S }, "你查看这本书.");
			DescriptionMapper.add("book-intro", { bookType: t_F }, "你检查这本书.");
			DescriptionMapper.add("book-intro", { bookType: t_H }, "你学习这本书.");
			DescriptionMapper.add("book-intro", { bookType: t_H }, "你粗略地翻阅这本书.");
			DescriptionMapper.add("book-intro", { bookType: t_E }, "你看了这本书.");

			DescriptionMapper.add("book-description", { bookType: wildcard }, "一段描述 [n-topic] 吸引你的眼睛.");
			DescriptionMapper.add("book-description", { bookType: wildcard }, "一段描述 [n-topic] 的内容似乎很有趣.");
			DescriptionMapper.add("book-description", { bookType: wildcard }, "你学到了关于 [n-topic] 的一些东西.");
			DescriptionMapper.add("book-description", { bookType: wildcard }, "这本书相当 [a-bad]，但你还是学到了一些东西.");

			DescriptionMapper.add("book-description", { bookLevel: l_1 }, "它让你对 [n-topic] 有了一些了解.");
			DescriptionMapper.add("book-description", { bookLevel: l_2 }, "它似乎是一个关于 [n-topic] 的好来源.");
			DescriptionMapper.add("book-description", { bookLevel: l_3 }, "这本书不容易跟随，但你从中学到了很多关于 [n-topic] 的东西.");

			DescriptionMapper.add("book-description", { bookType: t_S }, "这是一本关于 [n-topic] 的 [a] [a-level] 教科书.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "这是一本关于 [n-topic] 的 [a] [a-style] 教科书.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "这是一本关于 [n-topic] 的 [a] [a-good] 教科书.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "这是一本关于 [n-topic] 的 [a] [a-bad] 教科书，但你还是学到了一些新东西.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "它描述了 [n-topic].");
			DescriptionMapper.add("book-description", { bookType: t_S }, "书中有几处关于 [n-topic] 的有趣段落.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "这是一本相当枯燥的关于 [n-topic] 的文本.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "它包含了关于 [n-topic] 的描述.");
			DescriptionMapper.add("book-description", { bookType: t_S }, "你学到了 [c-fact].");
			DescriptionMapper.add("book-description", { bookType: t_S }, "你发现了 [c-fact].");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_1 }, "这是一本关于 [n-topic] 的入门文本.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_1 }, "这是一本关于 [n-topic] 的 [a] [a-bad] 书.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_1 }, "它包含了一些关于 [n-topic] 的基本信息.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_1 }, "一个关于精炼过程的描述提供了关于废墟前常用建筑材料的线索.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_1 }, "它包含了关于'黑暗层'已知动物生命的目录。你认识其中几个.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_2 }, "你注意到有关每天暴露在阳光下的人与那些没有的人之间的旧人口普查数据.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_2 }, "它包含了你不熟悉的基于太阳的日历系统的详细描述.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_2 }, "你发现了关于 [n-topic] 的详细信息.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_2 }, "它包含了关于 [n-topic] 的详细信息.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_3 }, "你被关于地面上丰富植物生命的描述所吸引.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_3 }, "书中关于 [n-topic] 的信息丰富.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_3 }, "它包含了关于 [n-topic] 的论文.");
			DescriptionMapper.add("book-description", { bookType: t_S, bookLevel: l_3 }, "它包含了关于 [n-topic] 的深入信息.");

			DescriptionMapper.add("book-description", { bookType: t_E }, "这是一本关于 [n-topic] 的 [a] [a-level] 教科书.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "这是一本关于 [n-topic] 的 [a] [a-style] 教科书.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "这是一本关于 [n-topic] 的 [a] [a-good] 教科书.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "这是一本关于 [n-topic] 的 [a] [a-bad] 教科书，但你还是学到了一些新东西.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "书中有关于 [n-object] 的废弃计划.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "它包含了关于 [n-object] 的详细描述.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "有一张详细解释 [n-object] 工作原理的图解.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "这是 [n-object] 的操作手册.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "你学到了很多关于 [n-object] 的信息.");
			DescriptionMapper.add("book-description", { bookType: t_E }, "你发现了 [c-fact].");
			DescriptionMapper.add("book-description", { bookType: t_S }, "你发现了 [c-fact].");
			DescriptionMapper.add("book-description", { bookType: t_E, bookLevel: l_1 }, "有一个关于 [n-object] 的有趣图解.");
			DescriptionMapper.add("book-description", { bookType: t_E, bookLevel: l_1 }, "它包含了一些关于 [n-topic] 的基本信息.");
			DescriptionMapper.add("book-description", { bookType: t_E, bookLevel: l_2 }, "它包含了关于 [n-topic] 的许多有用信息.");
			DescriptionMapper.add("book-description", { bookType: t_E, bookLevel: l_2 }, "它包含了关于 [n-topic] 的详细信息.");
			DescriptionMapper.add("book-description", { bookType: t_E, bookLevel: l_3 }, "书中有 [n-object] 的技术图纸.");
			DescriptionMapper.add("book-description", { bookType: t_E, bookLevel: l_3 }, "它包含了关于 [n-topic] 的深入信息.");

			DescriptionMapper.add("book-description", { bookType: t_H }, "你发现了关于 [n-topic] 的细节.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "它描述了 [n-topic].");
			DescriptionMapper.add("book-description", { bookType: t_H }, "它描述了 [c-event].");
			DescriptionMapper.add("book-description", { bookType: t_H }, "这是一本关于 [n-topic] 的相当枯燥的文本.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "它是关于 [n-topic] 的 [a] [a-style] 概述.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "它是对 [n-topic] 的非常 [a-level] 介绍.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "你了解到 [c-fact].");
			DescriptionMapper.add("book-description", { bookType: t_H }, "似乎 [c-fact].");
			DescriptionMapper.add("book-description", { bookType: t_H }, "你了解了 [c-event].");
			DescriptionMapper.add("book-description", { bookType: t_H }, "书中有一章关于 [c-event].");
			DescriptionMapper.add("book-description", { bookType: t_H }, "一个关于 [c-event] 的章节引起了你的注意.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "书中有几个对 [c-event] 的引用.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "这是对 [n-topic] 的 [a] 非常 [a-good] 解释.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "这本书总体上很乏味，但有一个关于 [n-topic] 的 [a] [a-good] 章节.");
			DescriptionMapper.add("book-description", { bookType: t_H }, "对城市\"当前无人居住的层级\"的提及提供了对废墟前城市的视角.");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_1 }, "这是一本关于 [n-topic] 的入门文本.");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_1 }, "它提到了 [c-event].");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_2 }, "书中有一长段关于 [c-event] 的内容.");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_2 }, "这是对 [n-topic] 的详细探讨.");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_3 }, "你获得了关于 [c-event] 的大量信息.");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_3 }, "你获得了关于 [n-topic] 的大量信息.");
			DescriptionMapper.add("book-description", { bookType: t_H, bookLevel: l_3 }, "你发现了 [c-event] 的详细时间表.");

			DescriptionMapper.add("book-description", { bookType: t_F }, "书中有一个关于 [c-theme] 的 [a-good] 故事.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "这是一个关于 [c-theme] 的故事.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "它讲述了 [c-theme].");
			DescriptionMapper.add("book-description", { bookType: t_F }, "一个关于 [c-theme] 的故事让你难以忘怀.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "你被一首关于 [c-theme] 的诗打动.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "它包含了对 [c-theme] 的 [a-good] 描述.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "它是一本关于 [n-topic] 的 [a-style] 小说.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "它是一本关于 [n-topic] 的 [a-style] 故事.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "这是一本非常 [a-style] 的 [n-topic] 书.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "这是一本关于 [n-topic] 的 [a-style] 故事.");
			DescriptionMapper.add("book-description", { bookType: t_F }, "这是一本关于 [n-topic] 的 [a-style] 短篇小说集.");
			DescriptionMapper.add("book-description", { bookType: t_F, bookLevel: l_1 }, "这是一本以 [n-topic] 为主题的儿童书.");
			DescriptionMapper.add("book-description", { bookType: t_F, bookLevel: l_1 }, "这是一个关于 [c-theme] 的简单故事.");
			DescriptionMapper.add("book-description", { bookType: t_F, bookLevel: l_2 }, "这是一本关于 [n-topic] 的经典小说.");
			DescriptionMapper.add("book-description", { bookType: t_F, bookLevel: l_2 }, "它是一本关于 [c-theme] 的 [a-style] 小说.");
			DescriptionMapper.add("book-description", { bookType: t_F, bookLevel: l_3 }, "这是一本关于 [n-topic] 的相当厚重的书.");
			DescriptionMapper.add("book-description", { bookType: t_F, bookLevel: l_3 }, "这是一本关于 [n-topic] 的 [a-good] 故事.");
		}

		function initNewspaperTexts() {
			var wildcard = DescriptionMapper.WILDCARD;

			let l_1 = 1;
			let l_2 = 2;
			let l_3 = 3;

			DescriptionMapper.add("newspaper-description", { itemLevel: wildcard }, "有一篇关于 [n-topic] 的社论。");
			DescriptionMapper.add("newspaper-description", { itemLevel: wildcard }, "有一篇关于 [n-topic] 的观点文章。");
			DescriptionMapper.add("newspaper-description", { itemLevel: wildcard }, "有一个关于 [c-event] 的大新闻。");
			DescriptionMapper.add("newspaper-description", { itemLevel: wildcard }, "本期的焦点是 [c-event]。");
			DescriptionMapper.add("newspaper-description", { itemLevel: l_3 }, "有一篇关于 [n-topic] 的调查报道。");
		}

		function initResearchPaperTexts() {
			var wildcard = DescriptionMapper.WILDCARD;

			let l_1 = 1;
			let l_2 = 2;
			let l_3 = 3;

			DescriptionMapper.add("researchpaper-description", { itemLevel: wildcard }, "这篇论文是关于 [n-topic] 的。");
			DescriptionMapper.add("researchpaper-description", { itemLevel: wildcard }, "你了解到 [c-fact]。");
			DescriptionMapper.add("researchpaper-description", { itemLevel: wildcard }, "你推断出 [c-fact]。");
			DescriptionMapper.add("researchpaper-description", { itemLevel: wildcard }, "看起来 [c-fact]。");
			DescriptionMapper.add("researchpaper-description", { itemLevel: l_1 }, "这是关于 [n-topic] 的基础概述。");
			DescriptionMapper.add("researchpaper-description", { itemLevel: l_2 }, "这是 [n-topic] 的大纲。");
			DescriptionMapper.add("researchpaper-description", { itemLevel: l_3 }, "这是对 [n-topic] 的详细分析。");
		}

		initSectorTexts();
		initWaymarkTexts();
		initBookTexts();
		initNewspaperTexts();
		initResearchPaperTexts();

		return TextConstants;

	});
